package org.webrtc.yl.WebSocket;

import android.util.Log;

import com.camera.base.wbmodels.WebrtcWebModel;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.IceCandidate;
import org.webrtc.SessionDescription;

import java.util.ArrayList;


public class AndroidDirectRTC {
    private static final String TAG = "AndroidDirectRTC";

    private final SignalingEventsListener events;

    private enum ConnectionState {NEW, CONNECTED, CLOSED, ERROR}

    private ConnectionState roomState;

    public AndroidDirectRTC(SignalingEventsListener events) {
        this.events = events;
        roomState = ConnectionState.NEW;

        onTCPConnected(true);
    }

    public void onTCPMessage(JSONObject json){
        if (json == null) return;
        Log.w(TAG, "onTCPMessage: "+ json.toString());
        try {
            //JSONObject json = new JSONObject(msg);
            String type = json.optString("type");
            switch (type) {
                case "candidate":
                    events.onRemoteIceCandidate(toJavaCandidate(json));
                    break;
                case "remove-candidates":
                    JSONArray candidateArray = json.getJSONArray("candidates");
                    IceCandidate[] candidates = new IceCandidate[candidateArray.length()];
                    for (int i = 0; i < candidateArray.length(); ++i) {
                        candidates[i] = toJavaCandidate(candidateArray.getJSONObject(i));
                    }
                    events.onRemoteIceCandidatesRemoved(candidates);
                    break;
                case "answer": {
                    SessionDescription sdp = new SessionDescription(
                            SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));
                    events.onRemoteDescription(sdp);
                    break;
                }
                case "offer": {
                    SessionDescription sdp = new SessionDescription(
                            SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));

                    AppRTCClient.SignalingParameters parameters = new AppRTCClient.SignalingParameters(
                            // Ice servers are not needed for direct connections.
                            new ArrayList<>(),
                            false, // This code will only be run on the client side. So, we are not the initiator.
                            sdp // offerSdp
                    );
                    roomState = ConnectionState.CONNECTED;
                    events.onConnectedToRoom(parameters);
                    break;
                }
                case "client": {
                    SessionDescription sdp = new SessionDescription(
                            SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp"));

                    AppRTCClient.SignalingParameters parameters = new AppRTCClient.SignalingParameters(
                            // Ice servers are not needed for direct connections.
                            new ArrayList<>(),
                            false, // This code will only be run on the client side. So, we are not the initiator.
                            sdp // offerSdp
                    );
                    roomState = ConnectionState.CONNECTED;
                    events.onConnectedToRoom(parameters);
                    break;
                }
                default:
                    reportError("Unexpected TCP message: " + json.toString());
                    break;
            }
        } catch (JSONException e) {
            reportError("TCP message JSON parsing error: " + e);
        }
    }
    public void onTCPMessage(WebrtcWebModel webrtcWebModel){
        if (webrtcWebModel == null) return;
        String type = webrtcWebModel.getType();
        switch (type) {
            case "candidate":
                events.onRemoteIceCandidate(new IceCandidate(
                        webrtcWebModel.getId(), webrtcWebModel.getLabel(), webrtcWebModel.getCandidate()));
                break;
            /* "remove-candidates":
                JSONArray candidateArray = json.getJSONArray("candidates");
                IceCandidate[] candidates = new IceCandidate[candidateArray.length()];
                for (int i = 0; i < candidateArray.length(); ++i) {
                    candidates[i] = toJavaCandidate(candidateArray.getJSONObject(i));
                }
                events.onRemoteIceCandidatesRemoved(candidates);
                break;*/
            case "answer": {
                SessionDescription sdp = new SessionDescription(
                        SessionDescription.Type.fromCanonicalForm(type), webrtcWebModel.getSdp());
                events.onRemoteDescription(sdp);
                break;
            }
            case "offer": {
                SessionDescription sdp = new SessionDescription(
                        SessionDescription.Type.fromCanonicalForm(type), webrtcWebModel.getSdp());

                AppRTCClient.SignalingParameters parameters = new AppRTCClient.SignalingParameters(
                        // Ice servers are not needed for direct connections.
                        new ArrayList<>(),
                        false, // This code will only be run on the client side. So, we are not the initiator.
                        sdp // offerSdp
                );
                roomState = ConnectionState.CONNECTED;
                events.onConnectedToRoom(parameters);
                break;
            }
            case "client": {
                SessionDescription sdp = new SessionDescription(
                        SessionDescription.Type.fromCanonicalForm(type), webrtcWebModel.getSdp());

                AppRTCClient.SignalingParameters parameters = new AppRTCClient.SignalingParameters(
                        // Ice servers are not needed for direct connections.
                        new ArrayList<>(),
                        false, // This code will only be run on the client side. So, we are not the initiator.
                        sdp // offerSdp
                );
                roomState = ConnectionState.CONNECTED;
                events.onConnectedToRoom(parameters);
                break;
            }
            default:
                reportError("Unexpected TCP message: " + webrtcWebModel.toString());
                break;
        }
    }

    private void reportError(final String errorMessage) {
        Log.e(TAG, errorMessage);
        /*executor.execute(() -> {
            if (roomState != ConnectionState.ERROR) {
                //2024.5.25 fzy del
                //roomState = ConnectionState.ERROR;
                //events.onChannelError(errorMessage);
            }
        });*/
    }

    private void onTCPConnected(boolean connectToRoom) {
        if (connectToRoom) {
            roomState = ConnectionState.CONNECTED;
            Log.e(TAG, "yulong   onTCPConnected: ConnectionState.CONNECTED ");

            AppRTCClient.SignalingParameters parameters = new AppRTCClient.SignalingParameters(
                    // Ice servers are not needed for direct connections.
                    new ArrayList<>(),
                    true, // Server side acts as the initiator on direct connections.
                    null// offerSdp
            );
            events.onConnectedToRoom(parameters);
        }
    }

    private static IceCandidate toJavaCandidate(JSONObject json) throws JSONException {
        return new IceCandidate(
                json.getString("id"), json.getInt("label"), json.getString("candidate"));
        /*return new IceCandidate(
                json.getString("sdpMid"), json.getInt("sdpMLineIndex"), json.getString("candidate"));*/
    }

    /**
     * Callback interface for messages delivered on signaling channel.
     *
     * <p>Methods are guaranteed to be invoked on the UI thread of `activity`.
     */
    public interface SignalingEventsListener {
        /**
         * Callback fired once the room's signaling parameters
         * SignalingParameters are extracted.
         */
        void onConnectedToRoom(final AppRTCClient.SignalingParameters params);

        /**
         * Callback fired once remote SDP is received.
         */
        void onRemoteDescription(final SessionDescription sdp);

        /**
         * Callback fired once remote Ice candidate is received.
         */
        void onRemoteIceCandidate(final IceCandidate candidate);

        /**
         * Callback fired once remote Ice candidate removals are received.
         */
        void onRemoteIceCandidatesRemoved(final IceCandidate[] candidates);

        /**
         * Callback fired once channel is closed.
         */
        void onChannelClose();

        /**
         * Callback fired once channel error happened.
         */
        void onChannelError(final String description);
    }
}
